from Tkinter import Canvas
from math import ceil

class ProgressBar(Canvas):
    def __init__(self, master, width=1200, height=20, command=None, user_setable=True):
        Canvas.__init__(self, master, width=width, height=height, bg="grey")
        self.width = width
        self.height = height
        self.command = command
        self.value = 0.0
        self.user_setable = user_setable
        self.setup()
        
    def setup(self):
        # setup an action when the canvas is clicked
        self.bind("<ButtonRelease-1>", self.user_set)
        self.bind("<Configure>", self.update_size)
        self.draw()
        
    def draw(self):
        # draw the bar
        pos = self.value * self.width
        self.create_rectangle(-self.width-10 + pos, 0, pos, self.height, 
                              fill="green", outline="green", tags=("bar",))
        # draw vertical lines every 10%
        tenth = self.width / 10.0
        for x in xrange(1, 10):
            x = ceil(x * tenth)
            self.create_line(x, 0, x, self.height, fill="white", tags=("marker",))
        # draw the percentage text
        self.create_text(0.5 * self.width, 0.5 * self.height, 
                         text="%.2f%%" % (self.value * 100,), tags=("progress",))
        
    def clear(self):
        self.delete("bar")
        self.delete("marker")
        self.delete("progress")
        
    def update_size(self, event=None):
        self.clear()
        self.width = self.winfo_width()
        self.height = self.winfo_height()
        self.draw()
        
    def set(self, value):
        assert 0.0 <= value <= 1.0
        old_pos = self.value * self.width
        new_pos = value * self.width
        self.move("bar", new_pos - old_pos, 0)
        self.itemconfigure("progress", text="%.2f%%" % (value * 100,))
        self.value = value
        
    def user_set(self, event):
        """Called when a user clicked the progress bar, so command must be invoked."""
        if self.user_setable:
            value = max(0.0, min(1.0, float(event.x) / self.width))
            self.set(value)
            if self.command is not None:
                self.command(value)
                
